import sys

from PyQt5 import QtCore
from PyQt5.QtCore import Qt, pyqtSignal, QTimer
from PyQt5.QtWidgets import QWidget, QApplication, QMessageBox
from PyQt5.QtWidgets import QFileDialog, QMessageBox, QWidget
from UI import untitled
from pythonProject.Network.Udp import get_host_ip
from UI.MyWidgets import PortInputDialog


class WidgetLogic(QWidget):
    '''

    '''
    link_signal = pyqtSignal(tuple)     #连接类型，目标IP，本机/目标端口
    disconnect_signal = pyqtSignal()
    send_signal =pyqtSignal(str)
    counter_signal = pyqtSignal(int,int)

    def __init__(self,parent=None):
        super().__init__(parent)
        self.__ui = untitled.Ui_MainWindow()
        self.__ui.setupUi(self)
        self.__ui.retranslateUi(self)

        self.setWindowFlags(Qt.WindowStaysOnTopHint)    #置顶
        self.setFixedSize(self.width()-240,self.height())

        self.__ui.MyHostAddrLineEdit.setText(get_host_ip())     #显示主机IP

        self.protocol_type = "TCP"
        self.link_flag = self.NoLink                #初始化为未连接状态
        self.receive_show_flag = True
        self.SendCounter = 0
        self.ReceiveCounter = 0
        self.dir = None


        '''槽函数'''

        self.counter_signal.connect(self.counter_signal_handler)
        self.__ui.ConnectButton.toggled.connect(self.connect_button_toggled_handler)
        self.__ui.ProtocolTypeComboBox.activated[str].connect(self.protocol_type_comobox_handler)       #选择类型
        self.__ui.SendButton.clicked.connect(self.send_link_handler)
        self.__ui.OpenFilePushButton.clicked.connect(self.open_file_handler)
        self.__ui.RSaveDataButton.clicked.connect(self.r_save_data_button_handler)
        self.__ui.CounterResetLable.clicked.connect(self.counter_reset_button_handler)          #检测鼠标点击这个lable的事件
        self.__ui.ReceivePauseCheckBox.toggled.connect(self.receive_pause_checkbox_toggled_handler)




    def connect_button_toggled_handler(self,state):
        '''
        连接的方法
        '''
        try:
            if state:
                # 按钮 连接
                self.click_link_handler()
            else:
                # 按钮 断开
                self.click_disconnect()
                self.editable(True)
        except Exception as ret:
            print(ret)

    def editable(self,able:bool=True)->None:
        '''
        当建立连接后，部分选型不可在修改
        '''
        self.__ui.ProtocolTypeComboBox.setDisabled(not able)
        self.__ui.MyHostAddrLineEdit.setReadOnly(not able)
        self.__ui.TargetIPLineEdit.setReadOnly(not able)
        self.__ui.TargetPortLineEdit.setReadOnly(not able)

    def protocol_type_comobox_handler(self,p_type):
        '''选择TCP,UDP,WEB的工作类型'''
        self.protocol_type = p_type
        print(self.protocol_type)
        if self.protocol_type == "Web Server":
            self.__ui.SendPlainTextEdit.setPlainText("请打开index.html所在的文件路径")
            self.__ui.SendPlainTextEdit.setEnabled(False)
            self.__ui.OpenFilePushButton.setText("选择路径")
        else:
            #恢复发送输入框可用
            self.__ui.SendPlainTextEdit.setEnabled(True)
            self.__ui.SendPlainTextEdit.clear()
            self.__ui.OpenFilePushButton.setText("打开文件")


    def click_link_handler(self)->None:
        '''按钮连接时的槽函数'''
        server_flag = False  # 如果没有输入目标IP与端口号，则作为Server使用
        target_ip = str(self.__ui.TargetIPLineEdit.text())

        def get_int_port(port):
            '''
            用户未输入端口则置为一
            '''
            if port == "":
                return -1
            else:
                return int(port)

        my_poty = get_int_port(self.__ui.MyPortLineEdit.text())
        target_port = get_int_port(self.__ui.TargetPortLineEdit.text())

        self.editable(False)            #不允许修改输入框

        if my_poty == -1 and target_port == -1 and target_ip == "":
            mb = QMessageBox(QMessageBox.Critical,"错误","请输入信息",QMessageBox.Ok,self)
            mb.open()
            self.editable(True)         #允许修改输入框
            self.__ui.ConnectButton.setChecked(False)
            return None
        elif my_poty != -1 and target_port != -1 and target_ip !="":
            mb = QMessageBox(QMessageBox.Critical,"错误","输入的信息过多",QMessageBox.Ok,self)
            mb.open()
            self.editable(True)
            self.__ui.ConnectButton.setChecked(False)
            return None

        elif target_port == -1 and target_ip =="":
            server_flag = True
        elif target_port == -1 and target_ip != "":
            input_d = PortInputDialog(self)
            input_d.setWindowTitle("服务启动失败")
            input_d.setLabelText("请输入目标端口号作为client的启动，或者取消")
            input_d.intValueSelected.connect(lambda val:self.__ui.TargetPortLineEdit.setText(str(val)))
            input_d.open()
            self.__ui.ConnectButton.setChecked(False)

            #提前终止槽函数
            return None

        elif target_port != -1 and target_ip =="":
            mb =QMessageBox(QMessageBox.Critical,"Client启动错误","请输入目标IP地址",QMessageBox.Ok,self)

            mb.open()
            self.__ui.ConnectButton.setChecked(False)

            #提前终止槽函数
            return None

        if self.protocol_type == "Web Server" and not self.dir:
            #处理用户未选择工作路径情况下连接网络
            self.dir = QFileDialog.getExistingDirectory(self,"选择index.html所在的工作路径","./")
            if self.dir:
                self.__ui.SendPlainTextEdit.clear()
                self.__ui.SendPlainTextEdit.appendPlainText(self.dir)
                self.__ui.SendPlainTextEdit.setEnabled(False)

            else:
                self.__ui.ConnectButton.setChecked(False)
                return None


        if self.protocol_type == "TCP" and server_flag:
            self.link_signal.emit((self.ServerTCP,"",my_poty))
            self.link_flag = self.ServerTCP
            self.__ui.StateLabel.setText("TCP服务端")
        elif self.protocol_type == "TCP" and not server_flag:
            self.link_signal.emit((self.ClientTCP,target_ip,target_port))
            self.link_flag = self.ClientTCP
            self.__ui.StateLabel.setText("TCP客户端")
        elif self.protocol_type == "UDP" and server_flag:
            self.link_signal.emit((self.ServerUDP,"",my_poty))
            self.link_flag = self.ServerUDP
            self.__ui.StateLabel.setText("UDP服务端")

            # TODO 作为UDP服务端时禁用发送
        elif self.protocol_type == "UDP" and not server_flag:
            self.link_signal.emit((self.ClientUDP,target_ip,target_port))
            self.link_flag = self.ClientUDP
            self.__ui.StateLabel.setText("UDP客户端")
        elif self.protocol_type == "Web Server":
            self.link_signal.emit((self.WebServer,"",my_poty))
            self.link_flag = self.WebServer
            self.__ui.StateLabel.setText("Web Server")



    def send_link_handler(self)->None:
        '''
        SendButton控件点击触发的槽
        '''
        if self.link_flag != self.NoLink:
            loop_flag = self.__ui.checkBox_4.checkState()  # 循环发送标识
            send_msg = self.__ui.SendPlainTextEdit.toPlainText()
            if loop_flag == 0:
                self.send_signal.emit(send_msg)
            elif loop_flag == 2:
                send_timer = QTimer(self)
                send_timer.start(int(self.__ui.doubleSpinBox.value()))
                send_timer.timeout.connect(lambda :self.send_signal.emit(send_msg))
                self.__ui.checkBox_4.stateChanged.connect(lambda val:send_timer.stop() if val == 0 else None)

                self.__ui.ConnectButton.toggled.connect(lambda val:send_timer.stop() if val == 0 else None)



    def msg_write(self,msg:str)->None:
        '''
        消息发送,QTextBrowser的对象没appendPlainText方法，需要把对象改为QPlainTextEdit类的对象，便解决问题
        '''
        try:
            # 显示接收的时间
            if self.receive_show_flag:
                self.__ui.ReceivePlainTextEdit.appendPlainText(msg)
        except Exception as ret:
            print(ret)



    def info_write(self,info:str,mode:int)->None:
        '''
        将接收到或已发送的消息写入ReceivePlainTextEdit
        :param info: 接收或发送的消息
        :param mode: 模式，接收/发送
        :return: None
        '''
        if self.receive_show_flag:
            if mode == self.InfoRec:
                self.__ui.ReceivePlainTextEdit.appendHtml(f'<font color = "blue">{info}</font>')
                self.ReceiveCounter += 1
                self.counter_signal.emit(self.SendCounter,self.ReceiveCounter)

            elif mode == self.InfoSend:
                self.__ui.ReceivePlainTextEdit.appendHtml(f'<font color = "green">{info}</font>')

            self.__ui.ReceivePlainTextEdit.appendHtml("\n")
        else:
            if mode == self.InfoRec:
                self.ReceiveCounter += 1
                self.counter_signal.emit(self.SendCounter,self.ReceiveCounter)



    def click_disconnect(self):
        '''
        点击断开按钮
        '''
        try:
            self.disconnect_signal.emit()
            self.link_flag = self.NoLink
            self.__ui.StateLabel.setText("未连接")
        except Exception as ret:
            print(ret)

    def counter_signal_handler(self,send_count,receive_count):
        '''
        控制收发计数器显示变化的槽函数
        '''
        self.__ui.SendCounterLabel.setText(str(send_count))
        self.__ui.ReceiveCounterLabel.setText(str(receive_count))


    def counter_reset_button_handler(self):
        '''
        清零收发计数器的槽函数
        '''
        try:
            self.SendCounter = 0
            self.ReceiveCounter = 0
            self.counter_signal.emit(self.SendCounter,self.ReceiveCounter)
        except Exception as ret:
            print(ret)
    def open_file_handler(self):
        '''
        打开文本文件，加载到发送PlainTextEdit
        '''
        if self.link_flag in [self.ServerTCP,self.ClientTCP,self.ClientUDP]:
            def read_file(file_dir):
                '''
                读取外部文件
                '''
                if file_dir:
                    try:
                        with open (file_dir,"r",encoding="UTF-8") as f:
                            self.__ui.SendPlainTextEdit.clear()
                            self.__ui.SendPlainTextEdit.appendPlainText(f.read())

                    except UnicodeDecodeError:
                        #如果不能用UTF8解码
                        mb = QMessageBox(QMessageBox.Critical,"无法读取文件，”无法读取文件，请检查输入",QMessageBox.Ok,self)
                        mb.exec_()


            fd = QFileDialog(self,"选择文件","./","文件文本（*,*）")
            fd.setAcceptMode(QFileDialog.AcceptOpen)
            fd.setFileMode(QFileDialog.ExistingFile)
            fd.fileSelected.connect(read_file)
            fd.open()

        elif self.link_flag == self.NoLink and self.protocol_type == "Web Server":
            self.dir = QFileDialog.getExistingDirectory(self,"选择index.html所在的路径","./")
            self.__ui.SendPlainTextEdit.clear()
            self.__ui.SendPlainTextEdit.appendPlainText(str(self.dir))
            self.__ui.SendPlainTextEdit.setEnabled(False)


    def r_save_data_button_handler(self):
        '''
        接收设置保存数据按键的槽函数
        '''
        text = self.__ui.ReceivePlainTextEdit.toPlainText()
        file_name = QFileDialog.getSaveFileName(self,"保存到txt","./","ALL(*, *);;txt文件(*.txt)","txt文件(*.txt)")[0]

        try:
            with open(file_name,mode="w")as f:
                f.write(text)
        except FileNotFoundError:
            pass# 如果用户取消输入，filename为空，会出现FileNotFoundError

    def receive_pause_checkbox_toggled_handler(self,ste:bool):
        '''
        暂停接受复选框的槽函数
        '''
        if ste:
            self.receive_show_flag = False
        else:
            self.receive_show_flag = True


    #   TODO 最小化到托盘
    NoLink = -1
    ServerTCP = 0
    ClientTCP = 1
    ServerUDP = 2
    ClientUDP = 3
    WebServer = 4
    InfoSend = 0
    InfoRec = 1


if __name__ == "__main__":

    app = QApplication(sys.argv)
    MainWindow = WidgetLogic()


    MainWindow.show()
    sys.exit(app.exec_())
